<template>
  <div class="container">
    <div class="chatBox">
        <SideBar :current-content="currentContent" @menu-change="menuChange"></SideBar>
        <KeepAlive>
          <component  :friendList="friendList"
                      :chatList="chatList"
                      :applicationList="applicationList"
                      :allChatRecords="allChatRecords"
                      @chatWith="chatWith"
                      :is="components[currentContent]"></component>
        </KeepAlive>

    </div>
        <div v-show="videoVisable" class="videobox">
          <div class="remoteVideo">
            <video ref="remoteVideo" style="height: 100%;width: 100%;"  autoplay></video>
            <div class="localVideo">
              <video ref="localVideo" muted="true" style="height: 100%;width: 100%;"  autoplay></video>
            </div>
          </div>
          <div><button @click="shutdownVideo">结束</button></div>
        </div>
        <div v-show="videoInviteVisable" class="videobox">
          <button @click="confirmInvite(true)">接受</button>
          <button @click="confirmInvite(false)">拒绝</button>
        </div>

    <div class="imgCheck" v-show="checkImageVisable" @click="closeImage">
      <div style="max-width: 70%;max-height: 100%;">
        <img style="width: 100%;" :src="imgSrc"/>
      </div>
      
    </div>
  </div>
</template>
<script setup lang="ts">
import {ref, shallowRef} from 'vue'
import {type WsMessage, type Relationship,type ChatUserInfo, type ChatRecord} from '@/types'
import chatUserApi from '@/api/chatUser';
import ChatUserRelationshipApi  from '@/api/chatUserRelationship'
import ChatUserApplicationApi from '@/api/ChatUserApplication';
import SideBar from '@/components/SideBar.vue';
import ChatView from './homechileview/ChatView.vue';
import FriendListView from './homechileview/FriendListView.vue';
import { useLoginUserStore } from '@/stores/loginUser';
import {handleNewApplication ,handleFriendRelationshipEstablish, handleNewMessageRecieve} from '@/wsMessageHandler'
import bus from '@/bus';
import authApi from '@/api/auth';
const checkImageVisable = ref(false)
const imgSrc = ref('')
bus.on('imageCheck',(src:unknown) => {
  console.log(src);
  imgSrc.value = src as string
  checkImageVisable.value = true
})
const closeImage = (e:any) =>{
console.log(e);
checkImageVisable.value = false
}
const loginUserStore = useLoginUserStore()
let rpcConnection:RTCPeerConnection | null
const ws = new WebSocket(`ws:10.12.36.178:8080/chat/ws?token=${loginUserStore.getToken()}`)
ws.onopen = () => {
  console.log('open');
}
ws.onmessage = (ev) => {
  const data:WsMessage = JSON.parse( ev.data)
  // console.log(data);
  handleMessage(data)
}
const handleMessage = (data:WsMessage) => {
  const en = data.eventName
  switch (en) {
    case 'EVENT_NEW_APPLICATION':handleNewApplication(data,applicationList);break
    case 'EVENT_NEW_FRIEND_RELATION_ESTABLISH':handleFriendRelationshipEstablish(data,friendList);break
    case 'EVENT_NEW_MESSAGE_RECEIVE':handleNewMessageRecieve(data,chatList,allChatRecords);break
    case 'EVENT_VIDEO_INVITE': handleVideoInvite(data);break
    case 'EVENT_NEGOTIATION_OFFER': handlerNegtiationOffer(data);break
    case 'EVENT_NEGOTIATION_ANSWER': handlerNegtiationAnswer(data);break
    case 'EVENT_CANDIDATE': handleCandidate(data);break;
    case 'EVENT_INVITE_CONFIRM': handleConfirm(data);break
    case 'EVENT_STOP_VIDEO': shutdown();break
  }
}

const handlerNegtiationOffer = async (data:any) => {
      console.log('recive offer -> send answer');
      
      initRPC()
      await rpcConnection?.setRemoteDescription(data.negotiation)
      await initLocalVideo()
      startStacks()
      await rpcConnection?.setLocalDescription()
      ws.send(JSON.stringify({
            eventName:'ON_NEGOTIATION_ANSWER',
            from:data.to,
            to: data.from,
            negotiation:rpcConnection!.localDescription
          }))

}
const handlerNegtiationAnswer = async (data:any) => {
  console.log('recieve answer');
  
  await rpcConnection?.setRemoteDescription(data.negotiation)
}

// const handleNegtiation = async (data:any) => {
  
//   console.log(data.negotiation.type);
//   console.log(rpcConnection!.signalingState);
  
//   const collision =   data.negotiation.type == 'offer' && (makingOffer.value || rpcConnection!.signalingState != 'stable')
//   if(collision){
//     console.log('abord');
    
//     return
//   }
//   console.log('设置描述' + data.negotiation.type);
//   await rpcConnection!.setRemoteDescription(data.negotiation)
//   if(data.negotiation.type == 'offer'){
//     await rpcConnection!.setLocalDescription()
//     console.log('send=>>' + rpcConnection!.localDescription?.type);
//     ws.send(JSON.stringify({
//             eventName:'ON_NEGOTIATION',
//             from:data.to,
//             to: data.from,
//             negotiation:rpcConnection!.localDescription
//           }))
//   }
// }
const handleCandidate = (data:any) => {
  if(!rpcConnection?.remoteDescription) {
    console.log('remoteDescription NOT SET !');
  }else {
    console.log('setting iceCandidate');
    
    rpcConnection!.addIceCandidate(data.candidate)
  }
  
}
const handleConfirm = (data:any) => {
  if(data.confirm) {
    startStacks()
  }
}
const videoInviteVisable = ref(false)
const handleVideoInvite = (data:any) => {
  videoInviteVisable.value = true
  videoTofriendName.value = data.from
}
const confirmInvite = (flag:boolean) => {
  videoInviteVisable.value = false
  if(flag) {
    videoVisable.value = true
    chatUserApi.videoInviteConfirm(true,videoTofriendName.value)
  }else {
  }
}
const currentContent = ref(0)

const chatList = ref<Array<ChatUserInfo>>([])
const applicationList = ref<Array<any>>([])
const friendList = ref<Array<Relationship>>([])// api get 
const allChatRecords = ref<Map<string,any>>(new Map())
const videoVisable = ref(false)
ChatUserRelationshipApi.getFriendList().then(res => {
  console.log(res.data);
  friendList.value = res.data.list
})
ChatUserApplicationApi.getApplications().then(res => {
  console.log(res.data);
  applicationList.value = res.data.list
})
chatUserApi.getLatelyChat().then(res =>{
  console.log(res.data);
  chatList.value = res.data.list
})
chatUserApi.getLatelyChatRecords().then(res => {
  allChatRecords.value = new Map(Object.entries(res.data.records_totalNumberOfRecords))
  console.log(allChatRecords.value);
  
})

const components = [
  ChatView,
  FriendListView,
]
const menuChange = (current:number) => {
     currentContent.value = current
}
const shutdownVideo = () => {
  shutdown()
  chatUserApi.stopVideo(videoTofriendName.value)
}
const isShutDown = ref(true)
const shutdown = () => {
  isShutDown.value = true
  videoInviteVisable.value = false;
  (localVideo!.value!.srcObject as MediaStream).getTracks().forEach(x => {
    x.stop()
  });

  if(remoteVideo.value?.srcObject){
    (remoteVideo!.value!.srcObject as MediaStream).getTracks()[0].stop()
  }

  if(rpcConnection){
    rpcConnection!.ontrack = null;
    rpcConnection!.onicecandidate = null;
    rpcConnection!.oniceconnectionstatechange = null;
    rpcConnection!.onsignalingstatechange = null;
    rpcConnection!.onicegatheringstatechange = null;
    rpcConnection!.onnegotiationneeded = null;
    
    rpcConnection!.close();
    rpcConnection = null
  }

  

  remoteVideo.value?.removeAttribute("src")
  remoteVideo.value?.removeAttribute("srcObject")
  localVideo.value?.removeAttribute("src")
  localVideo.value?.removeAttribute("srcObject")
  videoVisable.value = false
}
const chatWith = (userInfo:Relationship) => {
  currentContent.value = 0
  for (let index = 0; index < chatList.value.length; index++) {
    if (chatList.value[index].friendName == userInfo.friendName){
      return
    }
  }
  chatList.value.push({
    id:userInfo.id,
    friendName:userInfo.friendName,
    lastDate:new Date().getHours() + ':' + new Date().getMinutes(),
    lastMessage:''
  })
  if(allChatRecords.value.has(userInfo.id)){

  }else{
    // allChatRecords.value.set(userInfo.id,[])
  }
}
let video:MediaStream
const localVideo = ref<HTMLVideoElement>()
const remoteVideo = ref<HTMLVideoElement>()
const videoTofriendName = ref('')
const makingOffer = ref(false)
bus.on('startOnline',(friendName:any) => {
  console.log(friendName);
  videoTofriendName.value = friendName
  chatUserApi.checkOnline(friendName).then(res => {
    if(res.data.isOnline) {
        videoVisable.value = true
        navigator.mediaDevices.getUserMedia({audio:true,video:true}).then(mediaStream => {
        video = mediaStream
        localVideo!.value!.srcObject = video
        //发出视频请求
        chatUserApi.videoInvite(friendName)
        //直接开启webRTC 一系列
        initRPC()
        // startStacks()
       })   
    } 
  })
})
const initLocalVideo = async () => {
  video = await navigator.mediaDevices.getUserMedia({audio:true,video:true})
  localVideo!.value!.srcObject = video
}
const initRPC = () => {
  rpcConnection = new RTCPeerConnection({iceServers:[{urls:['stun:stun.voipbuster.com']}]})
        rpcConnection.onnegotiationneeded = () => {
          if(rpcConnection?.remoteDescription){
            console.log('remoteDescripton has already set ! no need for negotiation');
            
            return
          }
          makingOffer.value = true
          rpcConnection!.setLocalDescription().then(res => {
            console.log('send=>' + rpcConnection!.localDescription?.type);
            
              ws.send(JSON.stringify({
                eventName:'ON_NEGOTIATION_OFFER',
                from:loginUserStore.getUserName(),
                to: videoTofriendName.value,
                negotiation:rpcConnection!.localDescription
              }))
              makingOffer.value = false
          })
        }
        rpcConnection.onicecandidate = (e:RTCPeerConnectionIceEvent) => {
          const c = e.candidate
          console.log('开始发送地址');
          
          ws.send(JSON.stringify({
            eventName:'ON_CANDIDATE',
            from:loginUserStore.getUserName(),
            to: videoTofriendName.value,
            candidate:c
          }))
        }
        rpcConnection.ontrack = (e:RTCTrackEvent) => {
          const track = e.track
          console.log('设置远程');
          
          track.onunmute = () => {
            // if(remoteVideo.value?.srcObject) {
            //   return
            // }
            remoteVideo!.value!.srcObject = e.streams[0]
          }
        }
}
const startStacks = () => {
  const tracks = video.getTracks()
  console.log('开始推流');
  
  for(const t of tracks) {
    rpcConnection!.addTrack(t,video)
  }
}
</script>
<style scoped>
.container{
  position: relative;
  min-width: 1140px;
  height: 100%;
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
}
.chatBox {
  height: 800px;
  width: 1140px;
  border: 1px solid #CCC;
  border-radius: 10px;
  box-shadow: 0 0 10px blanchedalmond;
  display: flex;
  flex-direction: row;
}
.list {
  width: 315px;
  background-color: rgb(226, 223, 222);
}
.fade-enter-active,
.fade-leave-active{
  transition: opacity 0.3s ease;;
}
.fade-enter-from,
.fade-leave-to{
  opacity: 0;
}
/* .content {

} */
.videobox{
    position: absolute;
    height: 600px;
    width: 750px;
    border: 1px solid #CCC;
}
.remoteVideo {
  position: relative;
  height: 600px;
  width: 750px;
}
.localVideo {
  position: absolute;
  height: 150px;
  width: 300px;
  bottom: 450px;
  left: -50px;
}
.imgCheck {
  position: absolute;
  height: 100%;
  width: 100%;
  background-color: rgb(0, 0, 0,0.4);
  /* opacity: 0.3; */
  display: flex;
  justify-content: center;
  align-items: center;
}
</style>
